/*
 * @Copyright: CS of BIT
 * @Author: 王占坤
 * @File name: 
 * @Version: 
 * @Date: 2019-08-30 21:22:06 +0800
 * @LastEditTime: 2019-11-16 16:59:06 +0800
 * @LastEditors: 
 * @Description: 
 */

#include "Socket.h"

/**
 * @Author: 王占坤
 * @Description: 创建socket对象
 * @Param: int mode SOCK_STREAM是TCP模式，SOCK_DGRAM是UDP模式
 * @Param: int port 端口号
 * @Param: char* ip_addr ip地址,请填写服务器ip地址。
 * @Return: 
 * @Throw: 
 */
Socket::Socket(int mode, int port, char* ip_addr)
{
    this->mode_ = mode;
    this->port_ = port;
    strcpy(this->ip_, ip_addr);
    memset(this->data_, 0, sizeof(this->data_));
    this->protocol_=0;
}


Socket::~Socket()
{
}


/**
 * @Author: 王占坤
 * @Description: 创建socket进程.这里面封装的是socket函数，其中需要填若干参数，
 * 但是这些参数基本不需要特殊设置，因此没有留参数入口。如果需要可以手动更改。一般而言
 * 这里的参数足以应对绝大多数情况
 * @Return: socketfd 返回创建的socket句柄
 * @Throw: 
 */
socketfd Socket::createSocket()
{
    socketfd skf = socket(AF_INET, this->mode_, this->protocol_);

    if (skf == -1)//创建失败
    {
        perror("socket");
        printf("create socket error: %s(errno: %d)\n", strerror(errno), errno);
        return -1;
    }
    else
    {
        reUse(skf);
        return skf;
    }
}

/**
 * @Author: 王占坤
 * @Description: 初始化地址
 * @Param: struct sockaddr_in* addr  待初始化的地址指针
 * @Param：in_addr_t ip_addr, ip地址,NULL代表自动获取ip
 * @Param: int port， 端口号
 * @Return: void
 * @Throw: 
 */
void Socket::initialzeSocketaddr(struct sockaddr_in *addr, char *ip_addr)
{
    memset(addr, 0, sizeof(struct sockaddr_in));
    addr->sin_family = AF_INET;
    addr->sin_port = htons(port_);
    printf("addr = %s\n", ip_addr);

    if (ip_addr == NULL)
        addr->sin_addr.s_addr = htonl(INADDR_ANY);
    else
        addr->sin_addr.s_addr = inet_addr(ip_addr);
    
}

/**
 * @Author: 王占坤
 * @Description: 不允许外部调用.用于重用端口、地址
 * @Param: socketfd skf 传入需要进行服用的socketfd
 * @Return: NULL
 * @Throw: 
 */
void Socket::reUse(socketfd& skf)
{
    int optval = 1;
    int res = setsockopt(skf, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval));
    if (res == -1)
    {
        perror("setsockopt");
    }
}

/**
 * @Author: 王占坤
 * @Description: 从socket接受信息放到buff区，最大字节数为max_size
 * @Param: socketfd skf  信息源socket
 * @Param: char *buff  用于存储的缓冲
 * @Param: size_t n_bytes 最大接受多少字节的信息
 * @Param: int flag 一般传入为0即可
 * @Return: int 0:成功
 * @Throw: 
 */
int Socket::receiveMSG(socketfd skf, size_t n_bytes, int flag)
{
    memset(data_, 0, sizeof(data_));
    int num_of_reading_bytes = recv(skf, data_, BUFFER_SIZE, flag);
    // printf("num_of_reading_words: %d\n", num_of_reading_words);
    // printf("%s\n", buff);
    if (num_of_reading_bytes == -1) //失败
    {
        printf("receive message error: %s(errno: %d)\n", strerror(errno), errno);
    }
    return num_of_reading_bytes;
}

/**
 * @Author: 王占坤
 * @Description: 从buff向skf发送n_bytes个字节的数据
 * @Param: socketfd skf  目标socket
 * @Param: char* buff  缓冲区
 * @Param: size_t n_bytes 要发送的字节数目
 * @Param: int flag 默认为0
 * @Return: int 发送的数据量
 * @Throw: 
 */
int Socket::sendMSG(int skf, char *buff, size_t n_bytes, int flag)
{
    int num_of_sending_words = send(skf, buff, n_bytes, flag);
    if (num_of_sending_words == -1) //失败
    {
        printf("send message error: %s(errno: %d)\n", strerror(errno), errno);
    }
    return num_of_sending_words;
}
